/**
 * \file    state.h
 * \brief   Parser generator.
 * \author  Jérôme LAURENS
 * \version 0.1
 * \date    September 23, 2014
 *
 * Reads a LALR(1) grammar, generates a parser based on a template file.
 * This is based on lemon parser generator, but has strongly been
 * revisited.
 *
 */

#ifndef STATE_H
#define STATE_H

#include "common.h"
#include "item.h"
#include "action.h"
#include "symbol.h"

LPP_NAMESPACE_BEGIN

/* Each state of the generated parser's finite state machine
** is encoded as an instance of the expected_symbolsing structure. */


class State {
public:
    typedef State __self;
    Index id() const {/*! Sequential creation index for this state. */
        return state_id_m;
    }
    Index index() const {/*! Sequential index for this state. */
        return index_m;
    }
    void index(Index const i) {/*! Sequential index setter. */
        index_m = i;
    }
public:
    Generator & generator() const {
        return generator_m;
    }
    bool add_core_item(ItemRef const &I);
    ItemRefSet const & core_items() const {
        return core_items_m;
    }   /* The core Items for this state */
    ItemIndex number_of_core_items() const {
        return core_items_m.size();
    }

    ItemRefSet const & closure_items() const {  /*! All Items in this state. */
        return closure_items_m;
    }
    void swap_closure_items(ItemRefSet & items) {  /*! Setter. */
        closure_items_m.swap(items);
    }
    ItemRefList const & ordered_core_items() const {  /*! All Items in this state. */
        return ordered_core_items_m;
    }
    ItemRefList const & ordered_items() const {  /*! All Items in this state, ordered by build time. */
        return ordered_items_m;
    }
    void swap_ordered_items(ItemRefList & items) {  /*! Setter. */
        ordered_items_m.swap(items);
    }
    ActionRefList & actions() {
        return actions_m;
    }
    ActionRefList const & actions() const {
        return actions_m;
    }
    ActionRefList const & conflict_actions() const {
        return conflict_actions_m;
    }
    ActionRefMap const & terminal_actions() const {
        return terminal_actions_m;
    }
    ActionRefMap const & non_terminal_actions() const {
        return non_terminal_actions_m;
    }
    ActionIndex terminal_actions_count() {
        return terminal_actions_m.size();
    }
    ActionIndex non_terminal_actions_count() {
        return non_terminal_actions_m.size();
    }     /* Number of actions on terminals and non terminals */
    ActionRef const & action(SymbolRef const & lookahead) const {
        static ActionRef a;// null action
        if (terminal_actions_m.count(lookahead)) {
            return terminal_actions_m.at(lookahead);
        } else if (non_terminal_actions_m.count(lookahead)) {
            return non_terminal_actions_m.at(lookahead);
        } else {
            return a;
        }
    }
    static ActionOffset No_offset() {
        return std::numeric_limits<ActionOffset>().min();
    }
    State(Generator & __g, Index const i)
        : hash_m(0)
        , state_id_m(i)
        , index_m(i)
        , generator_m(__g)
        , terminal_offset_m(State::No_offset())
        , non_terminal_offset_m(State::No_offset()) {
//        DEBUG_MESSAGE(">>>>> NEW STATE: %lu", i);
    }
    ActionRef const & add_action(Action::Type const type, SymbolRef const & symbol);
    ActionRef const & add_reduce_action(SymbolRef const & lookahead, RuleRef const & rule);
    ActionRef const & add_shift_action(SymbolRef const & lookahead, StateRef const & next_state);
    ActionRef const & did_add_action();

    void compress_tables();

    void sort_actions() {
        DEBUG_MESSAGE("ACTION SORT of state: %lu...",index());
        std::sort(actions_m.begin(),actions_m.end());
        DEBUG_MESSAGE("ACTION SORT of state: %lu DONE",index());
    }

    size_t hash() {
        return hash_m;
    }
    bool has_no_terminal_offset() const {
        return terminal_offset_m==State::No_offset();
    }
    bool has_no_non_terminal_offset() const {
        return non_terminal_offset_m==State::No_offset();
    }
    ActionOffset & terminal_offset() {
        return terminal_offset_m;
    }
    ActionOffset & non_terminal_offset() {
        return non_terminal_offset_m;
    }

    SymbolRefSet const & terminal_lookaheads() const {    /*! All terminal lookaheads reachable from this state, after as many eductions as necessary. */
        return terminal_lookaheads_m;
    }
    bool insert_terminal_lookahead(SymbolRef const & symbol) {
        return terminal_lookaheads_m.insert(symbol).second;
    }

    String short_description() const {
        std::ostringstream oss;
        oss <<"state #"<<index()<<" => ";
        for (ItemRef const & item: core_items()) {
            oss<<Description()(item)<<"/";
        }
        return oss.str();
    }

#ifndef LPP_NO_DEFAULT_ACTIONS
    ActionRef const & default_terminal_action() const {
        return default_terminal_action_m;
    }/*! the most frequent terminal action. */
    ActionRef const & default_non_terminal_action() const {
        return default_non_terminal_action_m;
    }/*! the most frequent non terminal action. */
    void default_terminal_action(ActionRef const & action) {
        default_terminal_action_m = action;
    }/*! set the most frequent terminal action. */
    void default_non_terminal_action(ActionRef const & action) {
        default_non_terminal_action_m = action;
    }/*! set the most frequent non terminal action. */
    void setup_default_actions();
#endif

private:
    ItemRefSet core_items_m;         /* The core Items for this state */
    ItemRefList ordered_core_items_m;      /* All Items in this state */
    ItemRefSet closure_items_m;      /* All Items in this state */
    ItemRefList ordered_items_m;      /* All Items in this state */
    ActionRefList actions_m;       /* Set of actions for this state, no set because of Action mutability. */
    ActionRefList conflict_actions_m;       /* Set of conflict actions for this state. */
    ActionRefMap terminal_actions_m; /*! actions with terminal lookahead, by lookahead */
    ActionRefMap non_terminal_actions_m; /*! actions with non terminal lookahead, by lookahead */
    ActionRef default_terminal_action_m; /*! the most frequent terminal action */
    ActionRef default_non_terminal_action_m; /*! the most frequent non terminal action */
    SymbolRefSet terminal_lookaheads_m; /*! All terminal lookaheads reachable from this state, after as many eductions as necessary. */
    size_t hash_m;
    Index state_id_m;
    Index index_m;
    Generator & generator_m;            /*! Owner. */
    ActionOffset terminal_offset_m;
    ActionOffset non_terminal_offset_m;   /* yy_action[] offset for terminals and non terminals */

public:
    friend int compare(State const & __a, State const & __b);
};

LPP_NAMESPACE_END

#endif // STATE_H
